home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch03
/
linecalc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-21
|
12KB
|
419 lines
/****************************************************************
* FILE: linecalc.c
* DESC: These routines include the warping calculations and
* the line-handling functions.
*
* HISTORY: Created 3/11/1993
* LAST CHANGED: 5/ 6/1993
*
* Copyright (c) 1993 by Scott Anderson
*
****************************************************************/
/* ----------------------INCLUDES----------------------------- */
#include <conio.h>
#include <stdio.h>
#include <io.h>
#include <math.h>
#include <graph.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include "define.h"
/* -----------------------MACROS------------------------------ */
#define PIXEL(p,x,y) (p->pixmap[y * (long) p->wide + x])
#define SQUARE(x) (((long) x)*(x))
/* ----------------------PROTOTYPES--------------------------- */
/**** line routines ****/
int xorLine(int x1, int y1, int x2, int y2);
int getLine(int *argx1, int *argy1, int *argx2, int *argy2);
int findPoint(LINE_LIST *lineList, int * line, int * point,
int x, int y);
int movePoint();
/**** warping and morphing routines ****/
int sumLines(PICTURE *picture, COLOR *color, LINE *origline,
POINT *warp, LINE *warpline);
float getSourceLoc(POINT *orig, LINE *origline, POINT *warp,
LINE *warpline);
int setLength(LINE *line);
void setupScreen(PICTURE *pic, int editFlag);
/* ----------------------EXTERNALS---------------------------- */
/* set from last picture loaded */
extern int Xmin, Ymin, Xmax, Ymax;
extern int NumLines;
extern LINE SrcLine[MAX_LINES];
extern LINE DstLine[MAX_LINES];
/* ----------------------GLOBAL DATA-------------------------- */
int TargFlag=0;
/******** These are the basic warping calculations **********/
/*****************************************************************
* FUNC: int sumLines(PICTURE *picture, COLOR *color,
* LINE *origline, POINT *warp, LINE *warpline)
*
* DESC: Sum and weight the contribution of each warping line
*****************************************************************/
int
sumLines(PICTURE *picture, COLOR *color, LINE *origline,
POINT *warp, LINE *warpline)
{
int x, y;
float weight, weightSum;
float distance;
int line;
POINT orig;
int paletteIndex;
float deltaSumX = 0.0;
float deltaSumY = 0.0;
/* if no control lines, get an unwarped pixel */
if (NumLines == 0)
orig = *warp;
else {
weightSum = 0.0;
for (line = 0; line < NumLines; line++,
origline++, warpline++) {
distance = getSourceLoc(&orig,origline,warp,warpline);
weight = 1/(.001+distance*distance);
deltaSumX += (orig.x - warp->x) * weight;
deltaSumY += (orig.y - warp->y) * weight;
weightSum += weight;
}
orig.x = warp->x + deltaSumX / weightSum + .5;
orig.y = warp->y + deltaSumY / weightSum + .5;
}
/* clip it to the nearest border pixel */
x = clip(orig.x, Xmin, Xmax);
y = clip(orig.y, Ymin, Ymax);
paletteIndex = PIXEL (picture, x, y);
color->r = picture->pal.c[paletteIndex].r;
color->g = picture->pal.c[paletteIndex].g;
color->b = picture->pal.c[paletteIndex].b;
return (paletteIndex);
}
/*****************************************************************
* FUNC: float getSourceLoc(POINT *orig, LINE *origline,
* POINT *warp, LINE *warpline)
*
* DESC: For a given line, locate the corresponding warped pixel
*****************************************************************/
float
getSourceLoc(POINT *orig, LINE *origline, POINT *warp,
LINE *warpline)
{
float fraction, fdist;
int dx, dy;
float distance;
dx = warp->x - warpline->p[0].x;
dy = warp->y - warpline->p[0].y;
fraction = (dx * (long) warpline->delta_x + dy
* (long) warpline->delta_y)
/ (float) (warpline->length_square);
fdist = (dx * (long) -warpline->delta_y + dy
* (long) warpline->delta_x)
/ (float) warpline->length;
if (fraction <= 0 )
distance = sqrt(dx*(long) dx + dy * (long) dy);
else if (fraction >= 1) {
dx = warp->x - warpline->p[1].x;
dy = warp->y - warpline->p[1].y;
distance = sqrt(dx*(long) dx + dy * (long) dy);
}
else if (fdist >= 0)
distance = fdist;
else
distance = -fdist;
orig->x = origline->p[0].x + fraction * origline->delta_x -
fdist * origline->delta_y
/ (float) origline->length + .5;
orig->y = origline->p[0].y + fraction * origline->delta_y +
fdist * origline->delta_x
/ (float) origline->length + .5;
return distance;
}
/*****************************************************************
* FUNC: int setLength(LINE *line)
*
* DESC: Set the deltas, the length and the length squared
* for a given line.
*****************************************************************/
int
setLength (LINE *line)
{
line->delta_x = line->p[1].x - line->p[0].x;
line->delta_y = line->p[1].y - line->p[0].y;
line->length_square = SQUARE(line->delta_x)
+ SQUARE(line->delta_y);
line->length = sqrt(line->length_square);
}
/********************* The line routines **********************/
/*****************************************************************
* FUNC: int xorLine(int x1, int y1, int x2, int y2)
*
* DESC: Draw a line on the screen using the XOR of the
* screen index.
*****************************************************************/
int
xorLine(int x1, int y1, int x2, int y2)
{
int oldcolor = _getcolor();
_setcolor(WHITE); /* Use white as the xor color */
_setwritemode(_GXOR);
_moveto (x1,y1);
_lineto (x2,y2);
_setcolor(oldcolor); /* restore the old color */
}
/*****************************************************************
* FUNC: int getLine(int *argx1, int *argy1, int *argx2, int*argy2)
*
* DESC: Input a line on the screen with the mouse.
*****************************************************************/
int
getLine (int *argx1, int *argy1, int *argx2, int *argy2)
{
int x1,y1, x2,y2;
int oldx, oldy;
int input;
/* save the current mode */
short old_mode = _getwritemode();
/* get input until we have a real line, not just a point */
do {
/* wait for button or key press */
while (!(input = mousePos (&x1, &y1)));
if (input & KEYPRESS) {
_setwritemode(old_mode);
return 1;
}
oldx=x1, oldy=y1;
hideMouse();
/* prime the pump with this dot */
xorLine (x1, y1, oldx, oldy);
showMouse();
while (input = mousePos (&x2, &y2)) {
/* rubber band a line while the mouse is dragged */
if (x2 != oldx || y2 != oldy)
{
hideMouse();
xorLine (x1, y1, oldx, oldy);
xorLine (x1, y1, x2, y2);
showMouse();
oldx=x2, oldy=y2;
}
}
} while (x1 == x2 && y1 == y2);
*argx1 = x1, *argy1 = y1;
*argx2 = x2, *argy2 = y2;
_setwritemode(old_mode); /* get out of XOR mode */
return (0);
}
/*****************************************************************
* FUNC: int findPoint(LINE_LIST *lineList, int * line,
* int * point, int x, int y)
*
* DESC: loop thru dstline and find point within GRAB_DISTANCE,
* return 1 if found, 0 otherwise.
*****************************************************************/
int
findPoint (LINE_LIST *lineList, int * line, int * point,
int x, int y)
{
int l, p;
int minl, minp;
long length;
long minlength = SQUARE(640) + SQUARE(480);
for (l = 0; l < lineList->number; l++) {
for (p = 0; p <= 1; p++) {
length = SQUARE(lineList->line[l].p[p].x - x)
+ SQUARE(lineList->line[l].p[p].y - y);
if (length < minlength) {
minlength = length;
minl = l;
minp = p;
}
}
}
if (minlength > GRAB_DISTANCE)
return 0;
*line = minl;
*point = minp;
return 1;
}
/*****************************************************************
* FUNC: int movePoint(LINE_LIST *lineList)
*
* DESC: Grab a point and move it. Return 1 when key is pressed,
* else return 0.
*****************************************************************/
int
movePoint(LINE_LIST *lineList)
{
int stuckx, stucky, movex,movey;
int oldx, oldy;
int input;
int line, point;
/* save the current mode */
short old_mode = _getwritemode();
do {
/* keep getting input until we have a mouse button */
while (!(input = mousePos (&movex, &movey)));
if (input & KEYPRESS) {
_setwritemode(old_mode);
return 1;
}
if (!findPoint(lineList, &line, &point, movex, movey)) {
_setwritemode(old_mode);
return 0;
}
/* establish fixed end point */
stuckx = lineList->line[line].p[1-point].x;
stucky = lineList->line[line].p[1-point].y;
oldx=movex, oldy=movey;
hideMouse();
/* erase the old line */
xorLine (stuckx,
stucky,
lineList->line[line].p[point].x,
lineList->line[line].p[point].y);
/* and prime the pump with the new line */
xorLine (stuckx, stucky, oldx, oldy);
showMouse();
while (input = mousePos (&movex, &movey)) {
/* rubber band a line while the mouse is dragged */
if (movex != oldx || movey != oldy) {
hideMouse();
xorLine (stuckx, stucky, oldx, oldy);
xorLine (stuckx, stucky, movex, movey);
showMouse();
oldx=movex, oldy=movey;
}
}
} while (stuckx == movex && stucky == movey);
lineList->line[line].p[point].x = movex;
lineList->line[line].p[point].y = movey;
_setwritemode(old_mode); /* get out of XOR mode */
return (0);
}
/*****************************************************************
* FUNC: void createLines(PICTURE *pic, LINE_LIST *lineList)
*
* DESC: create a list of line segments for a picture
*****************************************************************/
void
createLines(PICTURE *pic, LINE_LIST *lineList)
{
setupScreen(pic, 0); /* set for enter prompt */
initMouse();
showMouse();
for (lineList->number = 0;lineList->number < MAX_LINES;
lineList->number++) {
if (getLine(&lineList->line[lineList->number].p[0].x,
&lineList->line[lineList->number].p[0].y,
&lineList->line[lineList->number].p[1].x,
&lineList->line[lineList->number].p[1].y))
break;
}
hideMouse();
}
/*****************************************************************
* FUNC: void editLines(PICTURE *pic, LINE_LIST *lineList)
*
* DESC: move around some existing lines
*****************************************************************/
void
editLines(PICTURE *pic, LINE_LIST *lineList)
{
int segment;
setupScreen(pic, 1); /* set for edit prompt */
initMouse();
for (segment = 0; segment < lineList->number; segment++) {
xorLine(lineList->line[segment].p[0].x,
lineList->line[segment].p[0].y,
lineList->line[segment].p[1].x,
lineList->line[segment].p[1].y);
}
showMouse();
/* move the endpoints around */
while(!movePoint(lineList));
hideMouse();
}
/*****************************************************************
* FUNC: void setupScreen(PICTURE *pic, int editFlag)
*
* DESC: Print a message introducing the screen, wait for input,
* then set the graphics mode and display the screen.
*****************************************************************/
void
setupScreen(PICTURE *pic, int editFlag)
{
static char *editMess[2] = {"enter", "edit"};
static char *targMess[2] = {"source", "target"};
setTextMode();
_settextposition(VTAB, HTAB);
printf("When you are ready to %s the control lines",
editMess[editFlag]);
_settextposition(VTAB+2, HTAB);
printf("for the %s image, press any key.",
targMess[TargFlag]);
waitForKey();
setGraphicsMode();
displayPicture(pic);
}